home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / mac / hypercrd / xcmd / dxcmds34.sit / Dartmouth XCMD's 3.4.3 / card_15168.txt < prev    next >
Text File  |  1990-04-17  |  17KB  |  540 lines

  1. -- card: 15168 from stack: in.3
  2. -- bmap block id: 15445
  3. -- flags: 4000
  4. -- background id: 7337
  5. -- name: SortFieldByItem
  6. ----- HyperTalk script -----
  7. on opencard
  8.   hide card field "source"
  9.   put empty into card field "sorted"
  10.   pass opencard
  11. end opencard
  12.  
  13. on Install
  14.   put ChooseTargetStack() into it
  15.   InstallResource XFCN,SortFieldByItem,it
  16. end Install
  17.  
  18. on closeCard
  19.   hide msg
  20. end CloseCard
  21.  
  22.  
  23. -- part 2 (field)
  24. -- low flags: 01
  25. -- high flags: 0007
  26. -- rect: left=290 top=64 right=288 bottom=398
  27. -- title width / last selected line: 0
  28. -- icon id / first selected line: 0 / 0
  29. -- text alignment: 0
  30. -- font id: 3
  31. -- text size: 9
  32. -- style flags: 0
  33. -- line height: 12
  34. -- part name: unsorted
  35.  
  36.  
  37. -- part 3 (button)
  38. -- low flags: 00
  39. -- high flags: 8003
  40. -- rect: left=65 top=298 right=320 bottom=187
  41. -- title width / last selected line: 0
  42. -- icon id / first selected line: 0 / 0
  43. -- text alignment: 1
  44. -- font id: 0
  45. -- text size: 12
  46. -- style flags: 0
  47. -- line height: 16
  48. -- part name: SortFieldByItem
  49. ----- HyperTalk script -----
  50. on mouseUp
  51.   put empty into card field "sorted"
  52.   put the ticks into t1
  53.   put SortFieldByItem(card field "unsorted",2) into card field "sorted"
  54.   put the ticks into t2
  55.   put "time: "&t2-t1&&"ticks"
  56.   get the number of lines in card field unsorted
  57.   put " for "&it&" lines" after msg
  58. end mouseUp
  59.  
  60.  
  61.  
  62. -- part 6 (button)
  63. -- low flags: 00
  64. -- high flags: 8003
  65. -- rect: left=299 top=298 right=320 bottom=438
  66. -- title width / last selected line: 0
  67. -- icon id / first selected line: 0 / 0
  68. -- text alignment: 1
  69. -- font id: 0
  70. -- text size: 12
  71. -- style flags: 0
  72. -- line height: 16
  73. -- part name: Show C Source
  74. ----- HyperTalk script -----
  75. on mouseUp
  76.   get the visible of card field "source"
  77.   set the visible of card field "source" to not it
  78.   if it is false then
  79.     set the name of me to "Hide C Source"
  80.   else
  81.     set the name of me to "Show C Source"
  82.   end if
  83. end mouseUp
  84.  
  85.  
  86.  
  87. -- part 8 (field)
  88. -- low flags: 01
  89. -- high flags: 0007
  90. -- rect: left=395 top=64 right=288 bottom=490
  91. -- title width / last selected line: 0
  92. -- icon id / first selected line: 0 / 0
  93. -- text alignment: 0
  94. -- font id: 3
  95. -- text size: 9
  96. -- style flags: 0
  97. -- line height: 12
  98. -- part name: sorted
  99.  
  100.  
  101. -- part 9 (field)
  102. -- low flags: 01
  103. -- high flags: 2007
  104. -- rect: left=18 top=33 right=288 bottom=291
  105. -- title width / last selected line: 0
  106. -- icon id / first selected line: 0 / 0
  107. -- text alignment: 0
  108. -- font id: 3
  109. -- text size: 10
  110. -- style flags: 0
  111. -- line height: 13
  112. -- part name: Documentation
  113.  
  114.  
  115. -- part 7 (field)
  116. -- low flags: 81
  117. -- high flags: 0007
  118. -- rect: left=18 top=31 right=290 bottom=489
  119. -- title width / last selected line: 0
  120. -- icon id / first selected line: 0 / 0
  121. -- text alignment: 0
  122. -- font id: 3
  123. -- text size: 10
  124. -- style flags: 0
  125. -- line height: 13
  126. -- part name: Source
  127.  
  128.  
  129. -- part contents for card part 7
  130. ----- text -----
  131. /* SortFieldByItem1.0d1.c */
  132. /* ┬⌐ Trustees of Dartmouth College */
  133. /* written in LightSpeed C  ┬⌐ Think Technologies, Inc */
  134. /* by Roger Brown 3/2/88  Courseware Development Group 11/19/88 */
  135.  
  136. /* Distribution version. Source is for THINK C┬⌐ version 4.0. */
  137.  
  138. /* version 1.0d1 uses international string comparison */
  139.  
  140. /* This is a HyperCard XFCN that sorts the lines of a HyperCard container
  141.      alphabetically according to the value of a specified item in the line.
  142.      There is no limit to the number of lines except for available memory.
  143.      It uses the Lightspeed C quicksort function and it is quite fast! Only 
  144.      one pass is made over the data to find line starts.
  145.      Case is ignored in this version.
  146.          
  147.      Syntax is:
  148.    
  149.               get SortFieldByItem(container,item)
  150.    
  151.              where    container is any hypercard container (field, variable), 
  152.                            presumed to be multi-lined.
  153.                       item is the number of the item in the line to use as
  154.                            the sort key.
  155.  
  156.              returns: a copy of the container sorted by line
  157.                            or error messages.
  158.             
  159.              ex.      get SortField(card field 1,2)
  160.                    
  161.       To compile: create a project with this,MacTraps, and the LSC┬« 
  162.       qsort.c file. Build as code resource type XFCN named SortFieldByItem.
  163. */
  164.  
  165. #include "MemoryMgr.h"
  166. #include "HyperXCmd.h"
  167. #include "XCmdGlue.inc.c"
  168. #include "SetUpA4.h"
  169.  
  170. #define memoryError -1            /* marks a memory allocation error */
  171. int *order;                                    /* points to the line order array (in heap) */
  172. Handle orderHandle;                     /* handle to the line order array */ 
  173. int *lineStarts;                            /* points to array of line starts (in heap) */
  174. Handle lsHandle;                           /* handle to the line starts array */      
  175. Handle theField;                           /* handle to the input copy of the container */
  176. Handle theUCASEField;                /* handle to an upper case version of container */
  177. Handle DoSort();                        /* the sorting routine */
  178. long sortItem;                         /* the number of the sort item */
  179.  
  180. #define NULL 0L
  181.  
  182. /* change a string to all upper case */
  183. ucase(s)
  184. char *s;
  185. {
  186.         int i;
  187.         char c;
  188.         
  189.         for (i=0;i<strlen(s);i++) {
  190.                 s[i] = toupper(s[i]);
  191.         }
  192. }
  193.  
  194. char ValidStrToNum(s,n)
  195. char *s;
  196. long *n; 
  197. /* check string for valid ascii and convert if ok. Return validity.
  198.     Input string is changed to Pascal format */
  199. {
  200.     int c,len;
  201.     
  202.     /* length must be < 32768 */
  203.     len = strlen(s);
  204.     if ((len<1)||(len>32768)) return FALSE;
  205.     /* all characters must be 0..9,-,+ */
  206.     for (c=0;c<len;c++) {
  207.         if ((s[c]<48)||(s[c]>57))
  208.             if ((s[c]!=45)&&(s[c]!=43)) return FALSE;
  209.     }
  210.     CtoPstr(s);
  211.     StringToNum(s,n);
  212.     return TRUE;
  213. }
  214.  
  215. /* Get HyperCard comma delimited item i from item list string inStr. Return it in outStr */
  216. /* item must be smaller than 255 characters */
  217.  
  218. GetHCItem(inStr,i,outStr)
  219. char *inStr,*outStr;
  220. int i;
  221. {
  222.     int c;                                           /* character pointer */
  223.     int len;                                         /* length to scan */
  224.     int count;                                       /* count of items found */
  225.     int j;                                           /* item byte count */
  226.     Str255 temp;                                     /* collect item here, hope its < 255 */
  227.     
  228.     count = j = 0;                                   /* initialize */
  229.     len = strlen(inStr);                             /* go this far, max */
  230.     for (c=0;c<len;c++) {
  231.         if (inStr[c]==',') {                         /* at an item boundary */
  232.             count = count + 1;                       /* bump counter */
  233.             if (count==i) break;                     /* if this is it, stop scanning */
  234.             j = 0;                                   /* else start on the next item */
  235.         }
  236.         else {
  237.             temp[j] = inStr[c];                      /* collect characters to return */
  238.             j++;                                     /* go to next */
  239.             if (j==255) {                            /* sorry, too big to store */
  240.                 strcpy(temp,"Error: Item > 255 characters.");
  241.                 return;                       
  242.             }
  243.             if (c==(len-1)) {                        /* last item, no comma */
  244.                 count = count+1;
  245.                 break;
  246.             }
  247.         }
  248.     }
  249.     if (count < i) strcpy(outStr,"");   /* no item there */
  250.     else {
  251.         temp[j] = 0;                                     /* make it a C string */
  252.         strcpy(outStr,temp);                             /* move to output string */
  253.     }
  254.     return;
  255. }
  256.  
  257. /* build a return result structure from a string */
  258.  
  259. ResultIs(paramPtr,theResult)
  260. XCmdBlockPtr    paramPtr;
  261. char *theResult;
  262. {
  263.     long len;
  264.     Handle resultHandle;
  265.     len = 1+strlen(theResult);
  266.     resultHandle = NewHandle(len);
  267.     BlockMove(theResult,*resultHandle,len);
  268.     paramPtr->returnValue = resultHandle;
  269. }
  270.  
  271.  
  272. /* Get all line starts in one sweep, changing CRs to 0 bytes so that
  273.     I have real C strings to work with later. Also process an upper case 
  274.     copy of the input data by changing CRs to 0s and upper casing 
  275.     everthing else. We process both copies because we want to sort the
  276.     upper case version but reassemble the result from the original. 
  277.    
  278.     Returns the number of lines found.
  279. */
  280.    
  281. GetLineStarts(source,ucSource)
  282. char *source,*ucSource;    /* the data source and a copy to ucase */
  283. {
  284.         int c;                                     /* character counter */
  285.         int l;                                     /* line counter */
  286.         long startsSize;                    /* size of the line starts array */
  287.         
  288.         /* allocate some memry to hold the line starts "array" */
  289.         startsSize = 128;                   /* arbitrary starting size */
  290.         lsHandle = NewHandle(startsSize*2);
  291.         if (lsHandle==NULL) {          /* handle error */
  292.                 SysBeep(60);
  293.                 return memoryError;
  294.         }
  295.         HLock(lsHandle);                  
  296.         lineStarts = (int *)*lsHandle;
  297.         
  298.         /* scan the input data to find line starts */
  299.         l = c = 0;
  300.         *lineStarts = 0;                             /* first line starts at byte 0 */
  301.         while (source[c] != 0) {               /* scan to end */
  302.                 if (source[c]==13) {            /* at end of a line */
  303.                         l++;
  304.                         *(lineStarts+l) = c+1;      /* next one starts here */
  305.                         source[c] = 0;                     /* change cr to 0 */
  306.                         ucSource[c] = 0;                 /* and do same to the ucase version */
  307.                         if (l==startsSize-10) {     /* need more room for line starts */
  308.                                 startsSize = startsSize + 128;
  309.                                 HUnlock(lsHandle);
  310.                                 SetHandleSize(lsHandle,startsSize*2);
  311.                                 if (lsHandle==NULL) {    /* oops, out of room */
  312.                                         SysBeep(60);
  313.                                         return memoryError;
  314.                                 }
  315.                                 HLock(lsHandle);
  316.                                 lineStarts = (int *)*lsHandle;  /* it might have moved */
  317.                         }
  318.                 }
  319.                 ucSource[c] = toupper(ucSource[c]);  /* change to ucase in line */
  320.                 c++;
  321.         }
  322.         if (source[c-1]==0) l--;           /* last line might not have CR */
  323.         return l+1;                         
  324. }
  325.  
  326.  
  327. /* Compare line i and line j. This function is an input to qsort. */
  328.  
  329. compare(i,j)
  330. int i,j;
  331. {
  332.     Str255 item1,item2;
  333.     int len1,len2;
  334.     
  335.     GetHCItem(*theUCASEField+*(lineStarts+order[i]),(int)sortItem,item1);
  336.     GetHCItem(*theUCASEField+*(lineStarts+order[j]),(int)sortItem,item2);
  337.     len1 = strlen(item1);
  338.     len2 = strlen(item2);
  339.     
  340.     return IUMagString(item1,item2,len1,len2);
  341. }
  342.  
  343. /* Swap line i with line j. This function is an input to qsort. */
  344.  
  345. swap(i,j)
  346. int i,j;
  347. {
  348.         int swap;
  349.         swap = order[i];             /* We don't swap them in place, just */
  350.         order[i] = order[j];       /* their positions in the order array */
  351.         order[j] = swap;
  352. }
  353.  
  354. /* Do the sort and return a handle to the sorted result */
  355.  
  356. Handle DoSort()
  357. {
  358.         Handle tempField;          /* handle to memory to build the result */
  359.         int i,j,next;
  360.         int numLines;
  361.         Str255 temp1;
  362.         OSErr err;
  363.         long orderSize;
  364.         long test;
  365.         char c;
  366.         int sLen,last;
  367.         
  368.         /* make a copy of the data to convert to upper case */
  369.         
  370.         theUCASEField = theField;
  371.         err = HandToHand(&theUCASEField);   
  372.         if (err != noErr) {                                /* some memory problem */
  373.                 tempField = NewHandle(32);       /* hope it fits */
  374.                 strcpy(*tempField,"Not enough memory to sort (1)");
  375.                 return tempField;
  376.         }
  377.         HLock(theUCASEField);                   /* lock these down so we use pointers to them */
  378.         HLock(theField);
  379.         
  380.         /* get line starts, number of lines, and an uppercase copy */
  381.         
  382.         numLines = GetLineStarts(*theField,*theUCASEField);
  383.         if (numLines == memoryError) {    /* some memory problem */
  384.                 tempField = NewHandle(32); 
  385.                 strcpy(*tempField,"Not enough memory to sort (2)");
  386.                 return tempField;
  387.         }
  388.         
  389.         /* allocate space for the order array */
  390.         
  391.         orderSize = (numLines+1)*2;             /* this is an integer array */
  392.         orderHandle = NewHandle(orderSize);
  393.         if (orderHandle==NULL) {                   /* some memory problem */
  394.                 tempField = NewHandle(32); 
  395.                 strcpy(*tempField,"Not enough memory to sort (3)");
  396.                 return tempField;
  397.         }
  398.         
  399.         /* lock it down so we can use a pointer to it */
  400.         
  401.         HLock(orderHandle);
  402.         order = (int *)*orderHandle;
  403.         
  404.          /* initialize the order list */
  405.          
  406.         for (i=0;i<numLines;i++)
  407.                 order[i] = i;    
  408.         
  409.         /* let LSC qsort do the hard work for us */
  410.         
  411.         qksort(numLines,compare,swap);
  412.         
  413.         /* Now build the sorted result: grab each line in the new order
  414.              as a C string and concatenate it to the result string. */
  415.         
  416.         tempField = theUCASEField;          /* resuse this memory, its the right size */
  417.         next = **tempField = 0;
  418.         for (i=0;i<numLines;i++) {
  419.                 sLen = 1+strlen(*theField+*(lineStarts+order[i]));
  420.                 for (j=0;j<sLen;j++,next++) {
  421.                         c = *(*theField+*(lineStarts+order[i])+j);
  422.                         if (c==0) c = '\15';      /* change 0s back to CRs */
  423.                         *(*(tempField)+next) = c;
  424.                 }
  425.         }
  426.         next--;
  427.         *(*(tempField)+next) = 0;         /* put a 0 terminator on the result */
  428.  
  429.         /* clean up */
  430.         
  431.         DisposHandle(orderHandle);
  432.         DisposHandle(lsHandle);
  433.         
  434.         /* return the result */
  435.         
  436.         return tempField;
  437. }
  438.  
  439.  
  440. /* XFCN entry point */
  441.  
  442. pascal void main(paramPtr)
  443. XCmdBlockPtr    paramPtr;
  444. {
  445.         Str255 paramStr;
  446.         /* Prepare to use globals */
  447.         
  448.         RememberA0();
  449.         SetUpA4();
  450.         
  451.         /* get the input container copy */
  452.         
  453.         MoveHHi(paramPtr->params[0]);
  454.         HLock(paramPtr->params[0]);
  455.         theField = (Handle)paramPtr->params[0];
  456.        
  457.         HLock(paramPtr->params[1]);
  458.         strcpy(paramStr,*(paramPtr->params[1]));
  459.         
  460.         if (ValidStrToNum(paramStr,&sortItem)==TRUE) {
  461.             /* do the sort */
  462.             paramPtr->returnValue = DoSort();
  463.         }
  464.         else {
  465.             strcpy(paramStr,"Error in item number");
  466.             ResultIs(paramPtr,paramStr);
  467.         }
  468.         
  469.         /* clean up */
  470.         HUnlock (paramPtr->params[0]);
  471.         HUnlock (paramPtr->params[1]);
  472.         RestoreA4(); 
  473.         return;
  474. }
  475.  
  476.  
  477.  
  478. -- part contents for card part 9
  479. ----- text -----
  480. SortFieldByItem version 1.0d1.c
  481. Roger Brown
  482.  
  483. SortFieldByItem is an XFCN that alphabetically sorts the lines of any HyperCard container using a specified item on the line as a sort key.  The inputs are a container and the number of the item to sort by.  The output is a sorted copy of the container data.
  484.  
  485. This XFCN will give the same result as SortField
  486. if there is only one item in each line and item 1 is the sort key.  It assumes that the sort item will be no longer than 255 characters.  If the sort item in a particular line begins with a space, it will appear first in the list, so BE CAREFUL!  Similarly if a line does not have an item in the sort item position, it will appear first in the list.
  487.  
  488. Like SortField, this XFCN is quick and there is no limit to the number of lines in the container, except for the absolute limit of available memory.
  489.  
  490. INVOKING SortFieldByItem
  491.  
  492.   get SortFieldByItem(container,sortItem)
  493.         
  494.    where   container is any HyperCard container
  495.                 item is the number of the item to use as
  496.                         a sort key                                   
  497.  
  498. EXAMPLE
  499.  
  500.  ex. put SortField(card field "source",2) into
  501.        card field "destination"
  502.  
  503.  
  504. REVISION HISTORY
  505. 1.0d0 First public release.
  506. 1.0d1 Uses international string comparisons.
  507.  
  508. -- part contents for card part 2
  509. ----- text -----
  510. Hanover,NH
  511. Boston,MA
  512. New York,NY
  513. San Diego,CA
  514. St. Louis,MO
  515. Seattle,WA
  516. Atlanta,GA
  517. Wilmington,DE
  518. Chicago,IL
  519. Houston,TX
  520. Denver,CO
  521. Columbus,OH
  522. Orlando,FL
  523. Washington,DC
  524.  
  525. -- part contents for card part 8
  526. ----- text -----
  527. San Diego,CA
  528. Denver,CO
  529. Washington,DC
  530. Wilmington,DE
  531. Orlando,FL
  532. Atlanta,GA
  533. Chicago,IL
  534. Boston,MA
  535. St. Louis,MO
  536. Hanover,NH
  537. New York,NY
  538. Columbus,OH
  539. Houston,TX
  540. Seattle,WA